
先对这两种形式的多态性进行分类和比较。

\hspace*{\fill} \\ %插入空行
\noindent
\textbf{术语}

动态和静态多态为不同的C++编程习惯提供了支持:

\begin{tcolorbox}[colback=webgreen!5!white,colframe=webgreen!75!black]
\hspace*{0.75cm}有关多态术语的详细讨论，请参见[CzarneckiEiseneckerGenProg]的第6.5到6.7节。
\end{tcolorbox}

\begin{itemize}
\item 
通过继承实现的多态是有界和动态的:

\begin{itemize}
\item[-]
有界意味着参与多态行为的类型的接口，是由公共基类的设计预先确定的(这个概念的其他术语描述是invasive和intrusive)。

\item[-]
动态意味着接口的绑定在运行时(动态)完成。
\end{itemize}

\item 
通过模板实现的多态性是无界和静态的:

\begin{itemize}
\item[-]
无界意味着参与多态行为的类型接口不是预先确定的(该概念的其他术语描述是noninvasive和nonintrusive)。

\item[-]
静态意味着接口的绑定在编译时完成(静态)。
\end{itemize}
\end{itemize}

严格地说，在C++语言中，动态多态性和静态多态性是有界动态多态性和无界静态多态性的快捷方式。其他语言中，也存在其他组合(例如，Smalltalk提供了无界的动态多态性)。在C++的上下文中，动态多态和静态多态这两个术语不会引起混淆。

\hspace*{\fill} \\ %插入空行
\noindent
\textbf{优势与不足}

C++中的动态多态性展示了以下优点:

\begin{itemize}
\item 
可以优雅地处理异构集合。

\item 
可执行代码的体积更小(只需要一个多态函数，而必须生成不同的模板实例来处理不同的类型)。

\item 
代码可以完全编译;因此不需要发布实现源(发布模板库通常需要发布模板实现的源代码)。
\end{itemize}

C++中的静态多态有这些优点:

\begin{itemize}
\item 
内置类型的集合很容易实现，接口通用性不需要通过公共基类来表示。

\item 
生成的代码可能更快(因为不需要指针，而且可以更频繁地内联非虚函数)。

\item 
若应用程序只执行了部分接口，仍然可以使用只提供部分接口的具体类型。
\end{itemize}

静态多态性通常认为比动态多态性更类型安全，因为所有绑定都在编译时检查。例如，模板实例化的容器中插入错误类型的对象没有危险。然而，需要指向公共基类的指针的容器中，这些指针有可能无意中指向不同类型的对象。

实践中，不同的语义假设隐藏在相同的接口后面时，模板实例化也会造成一些麻烦。当假定关联加法操作符的模板实例化了一个与该操作符无关的类型时，可能会发生意外。这种语义不匹配在基于继承的层次结构中很少发生，可能是因为更明确地指定了接口规范。

\hspace*{\fill} \\ %插入空行
\noindent
\textbf{两种形式结合}

当然，可以结合这两种形式的多态性。例如，可以从公共基类派生不同种类的几何对象，以便能够处理几何对象的异构集合。但仍然可以使用模板，为特定类型的几何对象编写代码。

继承和模板的结合将在第21章中进一步介绍，将看到如何将成员函数的虚态参数化，以及如何使用基于继承的奇异递归模板模式(CRTP)，为静态多态性提供灵活性。




























